package cn.com.dcsgo.strategy.impl;

import cn.com.dcsgo.config.WechatAuthConfig;
import cn.com.dcsgo.constant.AuthConstant;
import cn.com.dcsgo.domain.LoginMember;
import cn.com.dcsgo.mapper.LoginMemberMapper;
import cn.com.dcsgo.model.SecurityUser;
import cn.com.dcsgo.strategy.LoginStrategy;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;

/**
 * 小程序端用户登录策略实现类
 *
 * @author Dcsgo
 * @since 2025/9/19 14:48
 */
@Slf4j
@Service(AuthConstant.MEMBER_LOGIN)
public class MemberLoginStrategy implements LoginStrategy {
    @Resource
    private WechatAuthConfig wechatAuthConfig;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private LoginMemberMapper loginMemberMapper;

    @Override
    public UserDetails realLogin(String username) {
        // 微信小程序登录参考文档：https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
        String realWechatAuthUrl = String.format(wechatAuthConfig.getUrl(),
                wechatAuthConfig.getAppid(), wechatAuthConfig.getSecret(), username
        );
        String wechatAuthResult = restTemplate.getForObject(realWechatAuthUrl, String.class);
        JSONObject wechatAuthResultJson = JSON.parseObject(wechatAuthResult);
        assert wechatAuthResultJson != null : "微信登录认证返回结果转JSON失败";
        if (wechatAuthResultJson.containsKey("errmsg")) {
            throw new InternalAuthenticationServiceException(wechatAuthResultJson.get("errmsg").toString());
        }
        String openid = wechatAuthResultJson.get("openid").toString();
        if (!StringUtils.hasText(openid)) {
            log.error("Dcsgo:小程序端用户登录异常！微信登录认证过了，但返回的数据中没有拿到有效的openid");
            throw new InternalAuthenticationServiceException("登录异常，请稍后再次尝试登录");
        }
        LoginMember loginMember = loginMemberMapper.selectOne(
                new LambdaQueryWrapper<LoginMember>()
                        .eq(LoginMember::getOpenId, openid)
        );
        // 首次登录的用户需要将用户信息记录到member表中
        if (loginMember == null) {
            loginMember = registerMember(openid);
        }
        SecurityUser securityUser = new SecurityUser();
        securityUser.setStatus(loginMember.getStatus());
        securityUser.setUserId(loginMember.getId());
        securityUser.setLoginType(AuthConstant.MEMBER_LOGIN);
        securityUser.setUsername(openid);
        securityUser.setOpenid(openid);
        // 微信小程序端用户登录是不需要密码的，所以都使用统一密码：WECHAT 来适配 Security
        securityUser.setPassword("$2a$10$MPoNXzZdEThCTdWxkOhs0.Ca4CBwvqQZEM1jY2kzw774DHyNmYCaS");
        return securityUser;
    }

    public static void main(String[] args) {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        System.out.println(passwordEncoder.encode("WECHAT"));
    }

    /**
     * 将小程序用户添加到 member 表中
     *
     * @param openid 小程序用户唯一标识
     * @return 微信小程序端用户实体类
     */
    private LoginMember registerMember(String openid) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();
        LoginMember loginMember = new LoginMember();
        // 设置新用户相关信息
        loginMember.setOpenId(openid);
        loginMember.setStatus(1);
        loginMember.setUserLasttime(new Date());
        loginMember.setScore(0);
        loginMember.setUserRegip(request.getRemoteAddr());
        loginMember.setUserLastip(request.getRemoteAddr());
        loginMemberMapper.insert(loginMember);
        return loginMember;
    }
}
